﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Lextm.SharpSnmpLib.Pipeline;
using System.Globalization;
using System.Net.Sockets;
using System.Net;
using Lextm.SharpSnmpLib.Messaging;
using Microsoft.Practices.Unity;
using RemObjects.Mono.Helpers;
using System.Configuration;
using Lextm.SharpSnmpLib;
using System.Collections;

namespace SSNMP_Agent
{
    public partial class Form1 : Form
    {
        private SnmpEngine _engine;
        private SnmpApplicationFactory appFac;
        private const string StrAllUnassigned = "All Unassigned";

        public Form1()
        {
            _engine = Program.Container.Resolve<SnmpEngine>();
            _engine.ExceptionRaised += (sender, e) => MessageBox.Show(e.Exception.ToString());

            InitializeComponent();

            tstxtPort.Text = @"161";
            tscbIP.Items.Add(StrAllUnassigned);
            foreach (IPAddress address in Dns.GetHostEntry(string.Empty).AddressList.Where(address => !address.IsIPv6LinkLocal))
            {
                tscbIP.Items.Add(address);
            }

            tscbIP.SelectedIndex = 0;

            GetCommunity();
            ListenTrapsAndInforms();
        }

        private void StartListeners()
        {
            _engine.Listener.ClearBindings();

            int port = int.Parse(txtPort.Text, CultureInfo.InvariantCulture);
            _engine.Listener.AddBinding(new IPEndPoint(IPAddress.Any, port));

            port = int.Parse(tstxtPort.Text, CultureInfo.InvariantCulture);
            if (tscbIP.Text == StrAllUnassigned)
            {
                if (Socket.OSSupportsIPv4)
                {
                    _engine.Listener.AddBinding(new IPEndPoint(IPAddress.Any, port));
                }

                if (Socket.OSSupportsIPv6)
                {
                    _engine.Listener.AddBinding(new IPEndPoint(IPAddress.IPv6Any, port));
                }

                _engine.Start();
                return;
            }

            IPAddress address = IPAddress.Parse(tscbIP.Text);
            if (address.AddressFamily == AddressFamily.InterNetwork)
            {
                if (!Socket.OSSupportsIPv4)
                {
                    MessageBox.Show(Listener.ErrorIPv4NotSupported);
                    return;
                }

                _engine.Listener.AddBinding(new IPEndPoint(address, port));
                _engine.Start();
                return;
            }

            if (!Socket.OSSupportsIPv6)
            {
                MessageBox.Show(Listener.ErrorIPv6NotSupported);
                return;
            }

            _engine.Listener.AddBinding(new IPEndPoint(address, port));
            _engine.Start();
        }

        private void StopListeners()
        {
            _engine.Stop();
        }

        private void ListenTrapsAndInforms()
        {
            var trapv1 = Program.Container.Resolve<TrapV1MessageHandler>("TrapV1Handler");
            trapv1.MessageReceived += WatcherTrapV1Received;
            var inform = Program.Container.Resolve<InformRequestMessageHandler>("InformHandler");
            inform.MessageReceived += WatcherInformRequestReceived;
        }

        private void GetCommunity()
        {
            SortedList ls = _engine.GetCommunityNames();
            txtReadCommunity.Text = ((OctetString)ls["get"]).ToString();
            txtWriteCommunity.Text = ((OctetString)ls["set"]).ToString();
        }

        private void ChangeCommunity()
        {
            OctetString t = new OctetString(txtReadCommunity.Text);
            OctetString s = new OctetString(txtWriteCommunity.Text);
            _engine.SetCommunityNames(t, s);
        }

        private void btnListening_Click(object sender, EventArgs e)
        {
            if (_engine.Active)
            {
                StopListeners();
                btnListening.Text = "Start";
                groupBox1.Enabled = true;
                return;
            }

            if (SnmpMessageExtension.IsRunningOnMono && PlatformSupport.Platform != PlatformType.Windows &&
                Mono.Unix.Native.Syscall.getuid() != 0 && int.Parse(txtPort.Text, CultureInfo.InvariantCulture) < 1024)
            {
                MessageBox.Show(@"On Linux this application must be run as root for port < 1024.");
                return;
            }

            try
            {
                ChangeCommunity();
                StartListeners();
                btnListening.Text = "Stop";
                groupBox1.Enabled = false;
            }
            catch (PortInUseException ex)
            {
                MessageBox.Show(@"Port is already in use: " + ex.Endpoint, @"Error");
            }
        }

        private static void WatcherInformRequestReceived(object sender, InformRequestMessageReceivedEventArgs e)
        {
            MessageBox.Show(string.Format("Inform from {0}: {1}", e.Sender.Address.ToString(), e.InformRequestMessage));
        }

        private static void WatcherTrapV1Received(object sender, TrapV1MessageReceivedEventArgs e)
        {
            MessageBox.Show(string.Format("Trap from {0}: {1}", e.Sender.Address.ToString(), e.TrapV1Message));
        }
    }
}
